#include <sys/types.h>
#include <pthread.h>
#include <stdio.h>
#include <stdio.h>
#include <stdlib.h>

typedef struct _linknode
{
    int data;
    struct _linknode *next;
}linknode;

typedef struct _linklist
{
    int length;
    linknode *first;
    pthread_mutex_t link_lock;
}linklist;

typedef linknode *linknodeptr;

typedef linklist *linklistptr;

typedef struct _param
{
    linklistptr list;
    int *dataarray;
    int number;
}param;

void outputlinklist(linklistptr);

void initlinklist(linklistptr list)
{
    if (pthread_mutex_init(&list->link_lock, NULL) != 0)
        printf("can't get mutex_lock\n");
    else
        printf("successd init mutex_lock\n");

    if (pthread_mutex_lock(&list->link_lock) != 0)
        printf("init: can't lock\n");
    list->length = 0;
    list->first = NULL;
    if (pthread_mutex_unlock(&list->link_lock) != 0)
        printf("init: can't unlock\n");
}

void insertlinklist(linklistptr list, int data)
{
    if (pthread_mutex_lock(&list->link_lock) != 0)
        printf("insertlinklist: can't lock\n");
    linknodeptr templinknodeptr = NULL;
    linknodeptr currlinknodeptr = (linknodeptr)calloc(1, sizeof(linknode));
    currlinknodeptr->data = data;
    currlinknodeptr->next = NULL;
    if (list->length == 0)
    {
        list->first = currlinknodeptr;
        list->length = 1;
    }
    else
    {
        templinknodeptr = list->first;
        while (templinknodeptr->next != NULL)
            templinknodeptr = templinknodeptr->next;
        templinknodeptr->next = currlinknodeptr;
        list->length += 1;
    }
    outputlinklist(list);
    if (pthread_mutex_unlock(&list->link_lock) != 0)
        printf("insertlinklist: can't unlock\n");
}

int removelinklist(linklistptr list, linknodeptr node)
{
    pthread_mutex_lock(&list->link_lock);
    linknodeptr prelinknodeptr = NULL;
    linknodeptr currlinknodeptr = NULL;
    if (list == NULL)
        return -1;
    prelinknodeptr = list->first;
    currlinknodeptr = list->first;

    while (currlinknodeptr != NULL && currlinknodeptr != node)
    {
        prelinknodeptr = currlinknodeptr;
        currlinknodeptr = currlinknodeptr->next;
    }

    if (currlinknodeptr == NULL)
        return -1;
    prelinknodeptr->next = currlinknodeptr->next;
    free(currlinknodeptr);
    currlinknodeptr = NULL;
    pthread_mutex_unlock(&list->link_lock);
    return 0;
}

void insertlinklistarray(linklistptr currlinklistptr, int dataarray[], int number)
{
    int i = 0;
    while (i < number)
    {
        insertlinklist(currlinklistptr, dataarray[i++]);
    }
}

int destroylinklist(linklistptr list)
{
    linknodeptr nextlinknodeptr = NULL;
    linknodeptr currlinknodeptr = list->first;
    while (currlinknodeptr != NULL)
    {
        nextlinknodeptr = currlinknodeptr->next;
        free(currlinknodeptr);
        currlinknodeptr = NULL;
        if (nextlinknodeptr != NULL)
            currlinknodeptr = nextlinknodeptr;
        else
            break;
    }
    free(list);
    list = NULL;
    return 0;
}

int searchlinklist(const linklistptr list, int data)
{
    linknodeptr currlinknodeptr = list->first;
    while (currlinknodeptr != NULL)
    {
        if (currlinknodeptr->data == data)
        {
            printf("%d exist\n", data);
            return 0;
        }
        currlinknodeptr = currlinknodeptr->next;
    }
    printf("%d does not exist\n", data);
    return -1;
}

void outputlinklist(linklistptr list)
{
    linknodeptr currlinknodeptr = list->first;
    while(currlinknodeptr != NULL)
    {
        printf("%d-", currlinknodeptr->data);
        currlinknodeptr = currlinknodeptr->next;
    }
    printf("\n");
}

void *thread_call(void *arg)
{
    param *pparam = (param *)arg;
    insertlinklistarray(pparam->list, pparam->dataarray, pparam->number);
    pthread_exit((void *)0);
}

int main()
{
    int *dataarray = (int *)calloc(10, sizeof(int));
    int *dataarray2 = (int *)calloc(10, sizeof(int));
    linklistptr list = (linklistptr)calloc(1, sizeof(linklist));
    int i = 0;
    pthread_t t_id1;
    pthread_t t_id2;
    param tempparam1, tempparam2;
    tempparam1.list = list;
    tempparam1.dataarray = dataarray;
    tempparam1.number = 10;
    tempparam2.list = list;
    tempparam2.dataarray = dataarray2;
    tempparam2.number = 10;
    
    initlinklist(list);
    for (i = 0; i < 10; i ++)
    {
        dataarray[i] = i;
        dataarray2[i] = 10 + i;
    }
    if (pthread_create(&t_id1, NULL, thread_call, (void *)&tempparam1) != 0)
        printf("thread create error\n");
    if (pthread_create(&t_id2, NULL, thread_call, (void *)&tempparam2) != 0)
        printf("thread create error\n");
    sleep(5);
    searchlinklist(list, 19);
    searchlinklist(list, 8);
    
    destroylinklist(list);
    return 0;
}
